#include "TreeCreator.h"
#include "../../drawing.h"
#include "../../common.h"
#include "../../shaderManager.h"
#include "../../log.h"
#include <math.h>

#include "../../widgets.h"
#include "../../widgetsets.h"

#include <lightimage.h>

namespace Tmpl {

TreeCreator::TreeCreator()
{
	mBranch = &mSettings.trunk;
	mTree = 0;
	mSettings.seed = 1211;

	// ---------------- //
	// --- stem tab---- //
	// ---------------- //
	mTabStem = new OrdenedSet("Stem", 200, 800);
	mTabStem->SetOrdering(false, WidgetSet::SPREAD, WidgetSet::TOP);

	// --- Axis ---
	mTabStemAxis = new LabeledSet("Axis", 200, 130, 0, 0, true);
	mTabStemAxis->SetOrdering(false, WidgetSet::SPREAD, WidgetSet::TOP);
	mTabStem->AddWidget(mTabStemAxis);

	mTabStemAxisLength = new Slider("Length", 185, 12, 0, 0, true, 2);
	mTabStemAxisLength->SetRange(1.0, 100.0);
	mTabStemAxis->AddWidget(mTabStemAxisLength);
	mTabStemAxis->AddSpacing(2);

	mTabStemAxisVariation = new Slider("Variation", 185, 12, 0, 0, true, 2);
	mTabStemAxis->AddWidget(mTabStemAxisVariation);
	mTabStemAxis->AddSpacing(2);

	mTabStemAxisResolution = new Slider("Resolution", 185, 12);
	mTabStemAxisResolution->SetRange(3.0, 50.0);
	mTabStemAxis->AddWidget(mTabStemAxisResolution);
	mTabStemAxis->AddSpacing(2);

	mTabStemAxisBending = new Slider("Bending", 185, 12, 0, 0, true, 2);
	mTabStemAxis->AddWidget(mTabStemAxisBending);
	mTabStemAxis->AddSpacing(2);

	mTabStemAxisLightInfluence = new CurveGraph("Light Influence", 185, 50, 0, 0, Vec2f(0.0f,0.5f), Vec2f(1.0f,0.5f), Spline2f::SPLINE_BEZIER_QUAD);
	mTabStemAxis->AddWidget(mTabStemAxisLightInfluence);
	mTabStemAxis->AddSpacing(2);

	// --- Rendering ---
	mTabStemRendering = new LabeledSet("Rendering", 200, 150, 0, 0, true);
	mTabStemRendering->SetOrdering(false, WidgetSet::SPREAD, WidgetSet::TOP);
	mTabStem->AddWidget(mTabStemRendering);

	mTabStemRenderingRadius = new Slider("Radius", 185, 12, 0, 0, true, 2);
	mTabStemRenderingRadius->SetRange(0.1, 5.0);
	mTabStemRendering->AddWidget(mTabStemRenderingRadius);
	mTabStemRendering->AddSpacing(2);

	mTabStemRenderingSegments = new Slider("Segments", 185, 12);
	mTabStemRenderingSegments->SetRange(0.0, 24.0);
	mTabStemRendering->AddWidget(mTabStemRenderingSegments);
	mTabStemRendering->AddSpacing(2);

	mTabStemRenderingResolution = new Slider("Resolution", 185, 12);
	mTabStemRenderingResolution->SetRange(3.0, 50.0);
	mTabStemRendering->AddWidget(mTabStemRenderingResolution);
	mTabStemRendering->AddSpacing(2);

	mTabStemRenderingProfile = new CurveGraph("Profile", 185, 50, 0, 0, Vec2f(0.0f,1.0f), Vec2f(1.0f,0.0f), Spline2f::SPLINE_BEZIER_QUAD);
	mTabStemRendering->AddWidget(mTabStemRenderingProfile);
	mTabStemRendering->AddSpacing(2);

	// ---------------- //
	// --Branching tab- //
	// ---------------- //
	mTabBranching = new OrdenedSet("Branching", 200, 800);
	mTabBranching->SetOrdering(false, WidgetSet::SPREAD, WidgetSet::TOP);

	mTabBranchingOffsetInfluence = new CurveGraph("Offset Influence", 185, 50, 0, 0, Vec2f(0.0f,1.0f), Vec2f(1.0f,1.0f), Spline2f::SPLINE_BEZIER_QUAD);
	mTabBranching->AddWidget(mTabBranchingOffsetInfluence);
	mTabBranching->AddSpacing(2);

	mTabBranchingInheritRadius = new CheckBox("Inherit Radius", 185, 12);
	mTabBranching->AddWidget(mTabBranchingInheritRadius);
	mTabBranching->AddSpacing(2);

	mTabBranchingOffsetMin = new Slider("Min Offset", 185, 12, 0, 0, true, 2);
	mTabBranching->AddWidget(mTabBranchingOffsetMin);
	mTabBranching->AddSpacing(2);

	mTabBranchingOffsetMax = new Slider("Max Offset", 185, 12, 0, 0, true, 2);
	mTabBranching->AddWidget(mTabBranchingOffsetMax);
	mTabBranching->AddSpacing(2);

	mTabBranchingBranches = new Slider("Branches", 185, 12, 0, 0, true, 0);
	mTabBranchingBranches->SetRange(0.0, 100.0);
	mTabBranchingBranches->SetValue(10.0);
	mTabBranching->AddWidget(mTabBranchingBranches);
	mTabBranching->AddSpacing(2);

	mTabBranchingAxisVariation = new Slider("Axis Variation", 185, 12, 0, 0, true, 2);
	mTabBranchingAxisVariation->SetRange(0.0, 1.0);
	mTabBranching->AddWidget(mTabBranchingAxisVariation);
	mTabBranching->AddSpacing(2);

	// ---------------- //
	// -- Misc  ------- //
	// ---------------- //
	mTabs = new Tabs("Tab", 200, 800);
	mTabs->AddTab("Stem", mTabStem);
	mTabs->AddTab("Branching", mTabBranching);

	// Tree
	mTreeSet = new OrdenedSet("Tree", 200, 800);
	mTreeSet->SetOrdering(false, WidgetSet::LEFT, WidgetSet::TOP);

	mTreeSetBranchButtons = new OrdenedSet("BranchButtons", 200, 20);
	mTreeSetBranchButtons->SetOrdering(true, WidgetSet::LEFT, WidgetSet::SPREAD);
	mTreeSet->AddWidget(mTreeSetBranchButtons);

	mTreeSetNewSeed = new Button("New Seed", 65, 20);
	mTreeSetBranchButtons->AddWidget(mTreeSetNewSeed);

	mTreeSetBranchAdd = new Button("Add Branch", 65, 20);
	mTreeSetBranchButtons->AddWidget(mTreeSetBranchAdd);

	mTreeSetBranchDelete = new Button("Delete Branch", 70, 20);
	mTreeSetBranchButtons->AddWidget(mTreeSetBranchDelete);

	mTreeSetOverview = new SelectList("", 200, 200);
	mTreeSetOverview->AddItem("Root");
	mTreeSetOverview->SetSelected(0);
	mTreeSet->AddWidget(mTreeSetOverview);

	// Update
	BuildBranchList();
	Tick(0.0f);
}
TreeCreator::~TreeCreator()
{
	delete mTree;
}

void TreeCreator::SetPos(int x, int y)
{
	mPos = Vec2i(x,y);
	mTabs->SetPos(x,y);
	mTreeSet->SetPos(x, y+mTabs->GetSize().y);
}

void TreeCreator::SetSize(int w, int h)
{
	mTabs->SetSize(w,350);
	mTreeSet->SetSize(w,h-350);
}

void TreeCreator::Tick(float dt)
{
	bool update = false;
	mTabs->Tick(dt);
	mTreeSet->Tick(dt);

	// update seed
	if (mTreeSetNewSeed->IsClicked())
	{
		mSettings.seed = rand();
		update = true;
	}

	// update old branch
	if (mTabs->IsChanged() || !mTree) 
	{
		mBranch->axisBending = (float)mTabStemAxisBending->GetValue();
		mBranch->axisLength = (float)mTabStemAxisLength->GetValue();
		mBranch->axisResolution = (int)mTabStemAxisResolution->GetValue();
		mBranch->axisVariation = (float)mTabStemAxisVariation->GetValue();
		mBranch->axisLightInfluence = mTabStemAxisLightInfluence->GetValue();

		mBranch->renderProfile = mTabStemRenderingProfile->GetValue();
		mBranch->renderRadius = (float)mTabStemRenderingRadius->GetValue();
		mBranch->renderResolution = (int)mTabStemRenderingResolution->GetValue();
		mBranch->renderSegments = (int)mTabStemRenderingSegments->GetValue();

		mBranch->branchingOffsetInfluence = mTabBranchingOffsetInfluence->GetValue();
		mBranch->branchingInheritRadius = mTabBranchingInheritRadius->IsChecked();
		mBranch->branchingOffsetMin = (float)mTabBranchingOffsetMin->GetValue();
		mBranch->branchingOffsetMax = (float)mTabBranchingOffsetMax->GetValue();
		mBranch->branchingBranches = (int)mTabBranchingBranches->GetValue();
		mBranch->branchingAxisVariation = (float)mTabBranchingAxisVariation->GetValue();

		update = true;
	}

	// did we create a branch?
	if (mTreeSetBranchAdd->IsClicked()) 
	{
		TreeBranchSettings branch = *mBranch;
		branch.axisLength = Max(0.5f, branch.axisLength * 0.75f - 1.0f);
		branch.renderSegments = Max(3, branch.renderSegments - 1);
		branch.childs.clear();
		mBranch->childs.push_back(branch);
		BuildBranchList();	

		update = true;
	}
	// did we delete a branch?
	else if (mTreeSetBranchDelete->IsClicked()) 
	{
		int current = 0;
		DeleteBranch(&mSettings.trunk, current, mTreeSetOverview->GetSelected());
		mTreeSetOverview->SetSelected(0);	
		BuildBranchList();	

		update = true;
	}
	// did we change selected branch
	else if (mTreeSetOverview->IsChanged())
	{
		BuildBranchList();	
	}

	// rebuild the tree
	if (update) 
	{
		if (mTree) delete mTree;
		mTree = new Tree(mSettings);
	}

}
void TreeCreator::Draw()
{
	mTabs->Draw();
	mTreeSet->Draw();
}

// Branch functions
void TreeCreator::BuildBranchListSub(const TreeBranchSettings* branch, std::string prefix)
{
	mTreeSetOverview->AddItem(std::string(prefix + " Branch").c_str());
	for (unsigned int i=0; i<branch->childs.size(); ++i)
	{
		BuildBranchListSub(&branch->childs[i], "--" + prefix);
	}
}
void TreeCreator::BuildBranchList()
{
	int idx = mTreeSetOverview->GetSelected();
	mTreeSetOverview->Clear();
	mTreeSetOverview->AddItem("Root");
	for (unsigned int i=0; i<mSettings.trunk.childs.size(); ++i)
	{
		std::string prefix = "--";
		BuildBranchListSub(&mSettings.trunk.childs[i], prefix);
	}
	 mTreeSetOverview->SetSelected(idx);

	// update current
	int current = 0;
	mBranch = GetBranch(&mSettings.trunk, current, idx);

	mTabStemAxisBending->SetValue(mBranch->axisBending);
	mTabStemAxisLength->SetValue(mBranch->axisLength);
	mTabStemAxisResolution->SetValue(mBranch->axisResolution);
	mTabStemAxisVariation->SetValue(mBranch->axisVariation);
	mTabStemAxisLightInfluence->SetValue(mBranch->axisLightInfluence);

	mTabStemRenderingProfile->SetValue(mBranch->renderProfile);
	mTabStemRenderingRadius->SetValue(mBranch->renderRadius);
	mTabStemRenderingResolution->SetValue(mBranch->renderResolution);
	mTabStemRenderingSegments->SetValue(mBranch->renderSegments);

	mTabBranchingOffsetInfluence->SetValue(mBranch->branchingOffsetInfluence);
	mTabBranchingInheritRadius->SetChecked(mBranch->branchingInheritRadius);
	mTabBranchingOffsetMin->SetValue(mBranch->branchingOffsetMin);
	mTabBranchingOffsetMax->SetValue(mBranch->branchingOffsetMax);
	mTabBranchingBranches->SetValue(mBranch->branchingBranches);
	mTabBranchingAxisVariation->SetValue(mBranch->branchingAxisVariation);
}
TreeBranchSettings* TreeCreator::GetBranch(TreeBranchSettings* in, int& current, int getIdx)
{
	if (current == getIdx) return in;
	for (unsigned int i=0; i<in->childs.size(); ++i)
	{
		++current;
		TreeBranchSettings* branch = GetBranch(&in->childs[i], current, getIdx);
		if (branch) return branch;
	}
	return 0;
}
void TreeCreator::DeleteBranch(TreeBranchSettings* in, int& current, int deleteIdx)
{
	for (unsigned int i=0; i<in->childs.size(); ++i)
	{
		++current;
		if (current == deleteIdx)
		{
			in->childs.erase(in->childs.begin() + i);
			return;
		}
		else
		{
			DeleteBranch(&in->childs[i], current, deleteIdx);
		}
	}
}


}